/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2020-2022. All rights reserved.
 * Description: 集合通信算子插件头文件
 * Author: liubanglan
 * Create: 2020-04-30
 */

#ifndef NETWORK_MANAGER_PUB_H
#define NETWORK_MANAGER_PUB_H

#include <map>
#include <mutex>
#include <atomic>
#include "hccl/base.h"
#include "hccl_common.h"
#include "hccl_inner_common.h"
#include "hccl_ip_address.h"
#include "adapter_hccp.h"
#include "tsd/tsd_client.h"

namespace hccl {
enum class SocketRole {
    SOCKET_ROLE_SERVER = 0,          /* server的角色 */
    SOCKET_ROLE_CLIENT = 1,          /* client的角色 */
    SOCKET_ROLE_RESERVED             /* 不参与socket连接 */
};

constexpr s32 CONNECT_FAIL = 0;    /* 连接失败 */
constexpr s32 CONNECT_OK = 1;     /* 连接成功 */
constexpr u32 DEFAULT_PHY_ID = INVALID_UINT;
constexpr u32 NO_LISTEN_PORT = INVALID_UINT;
constexpr s32 FIRST_LISTEN = 1;    /* 首次监听 */
constexpr s32 LAST_RELEASE = 0;    /* 最后释放 */
constexpr u64 TSD_OPEN_EXT_PARA_NUM = 2UL;
constexpr s32 BACKUP_DEVICE_LOG_DEV_VERSION = 0x72318; // MAJOR:0x07, MINOR:0x23, PATCH:0x18

class NetworkManager {
public:
    class InitTool;
    static NetworkManager &GetInstance(s32 deviceLogicID);
    // 初始化网卡，enableWhitelistFlag决定是否感知白名单disable配置
    HcclResult Init(NICDeployment nicDeploy, bool enableWhitelistFlag = false, u32 devicePhyId = DEFAULT_PHY_ID,
        bool isHostUseDevNic = false, bool hasBackup = false);
    HcclResult DeInit(NICDeployment nicDeploy, bool resetDeviceFlag = false, bool hasBackup = false);
    HcclResult HeterogInit(u32 devId, const HcclIpAddress &ipAddr, u32 port);
    HcclResult HeterogDeinit(u32 devId, const HcclIpAddress &ipAddr, u32 port);
    HcclResult StartVnic(HcclIpAddress localIp, u32 &port);
    HcclResult StopVnic();
    // port值为无效值0xFFFFFFFF时, 只初始化nic网卡，不启动监听
    HcclResult StartNic(const HcclIpAddress &ipAddr, u32 &port, bool rdmaFlag,
        HcclIpAddress ipAddrBackup = HcclIpAddress(0));
    HcclResult StopNic(const HcclIpAddress &ipAddr, u32 port);
    HcclResult StartHostNetAndListen(const HcclIpAddress &ipAddr, SocketHandle &socketHandle, u32 &port, bool rdmaFlag);
    HcclResult StopHostNetAndListen(SocketHandle socketHandle, const HcclIpAddress &ipAddr, u32 port);
    HcclResult StartHostNet(const HcclIpAddress &ipAddr, SocketHandle &socketHandle);
    HcclResult StopHostNet(SocketHandle socketHandle, const HcclIpAddress &ipAddr);
    HcclResult GetRaResourceInfo(RaResourceInfo &raResourceInfo);
    HcclResult Destroy();
    HcclResult HeterogStartListen(const HcclIpAddress &ipAddr, u32 port);
    HcclResult HeterogStopListen(const HcclIpAddress &ipAddr, u32 port, bool isNeedDeinit = false);
    HcclResult PsWorkerRaInit(u32 devId, const HcclIpAddress &ipAddr, u32 port, bool isHostUseDevNic = false,
        bool remoteIsHdc = false, bool isBoardVersion = false);
    HcclResult PsWorkerRaDeinit(u32 devId, const HcclIpAddress &ipAddr, u32 port);
    HcclResult InitRdmaHandle(u32 devId, const HcclIpAddress &ipAddr, bool disabledLiteThread = false,
        bool enable910ALite = false);
    HcclResult PingMeshRaPingInit(u32 devLogicId, u32 devPhyId, ra_init_config *config);
    HcclResult PingMeshRaPingDeinit();
    bool GetRdmaLiteStatus();
    bool IsHasStartVnic();
    HcclResult GetRdmaHandleByIpAddr(const HcclIpAddress &ipAddr, RdmaHandle &rdmaHandle);
private:
    friend InitTool;
    NetworkManager();
    ~NetworkManager();
    HcclResult TsdCapabilityGet(bool &supportMultiProcHCCP);
    HcclResult TsdProcessOpen(bool hasBackup);
    HcclResult InitHostSocket(const HcclIpAddress &addr, SocketHandle &socketHandle) const;
    HcclResult InitDeviceSocket(u32 devicePhysicID, const HcclIpAddress &ipAddr, SocketHandle &socketHandle);
    HcclResult InitRDMA(u32 devicePhysicID, const HcclIpAddress &ipAddr, network_mode netMode, notify_type notifyType,
        RdmaHandle &rdmaHandle, bool disabledLiteThread = false, bool enable910ALite = false,
        HcclIpAddress ipAddrBackup = HcclIpAddress(0));
    HcclResult StartListenSocket(const SocketHandle socketHandle, u32 &port) const;
    HcclResult StopListenSocket(const SocketHandle socketHandle, u32 port) const;
    HcclResult CheckSocketInfo(const SocketHandle socketHandle, const HcclIpAddress &ipAddr,
        u32 port = NO_LISTEN_PORT) const;
    HcclResult StopNicsSocketListen(const HcclIpAddress &ipAddr, u32 port);
    HcclResult StopNicsSocket(const HcclIpAddress &ipAddr);
    HcclResult StopAllDeviceNicSockets();
    HcclResult StopAllHostNicSockets();
    void DestroyRaVnicResource();
    HcclResult GetNotifyType(notify_type &notifyType) const;
    void GetNetworkMode(network_mode &netMode) const;
    HcclResult CheckAutoListenVersion(bool isAutoPort);

    HcclResult CloseHccpSubProc();
    HcclResult CloseHccpProcess(ProcOpenArgs &hccpProcessInfo);
    void GetDeviceRaInitConfig(ra_init_config &config);

    s32 deviceLogicId_;
    u32 devicePhyId_;
    bool vnicListened_ = false;
    bool isHostUseDevNic_ = false;
    bool isRdmaLiteEn_ = false;
    bool isRaInitRepeated_ = false;
    bool isRaDeInit_ = false;
    RaResourceInfo raResourceInfo_;
    Referenced deviceNicInitRef_;
    Referenced hostNicInitRef_;
    Referenced deviceVnicSocketRef_;
    std::map<HcclIpAddress, Referenced> hostNicSocketClientRef_;
    std::map<HcclIpAddress, std::map<u32, Referenced>> IPPortListenRefMapHost_;
    std::map<HcclIpAddress, std::map<u32, Referenced>> IPPortListenRefMapDevice_;
    std::mutex raLock_;
    std::mutex hccpProcInfoMutex_;
    notify_type notifyType_;
    static NetworkManager* nmInstance[MAX_DEV_NUM];
    pid_t subPid_{ 0 };
    u32 vnicPort_ = HETEROG_CCL_PORT;
    bool isTsdOpened_{false};
    ProcOpenArgs hccpProcessInfo_ {};               // 记录hccp的进程信息(Pid粒度)
};

class NetworkManager::InitTool {
public:
    InitTool();
    ~InitTool();
private:
    static std::atomic<unsigned> initCount;
};

static NetworkManager::InitTool g_networkManagerInit; // 关键变量

}

#endif
